#!/bin/bash

# created by vector sigma on July 15 2019
# github version

# Linux users should be able to use this wrapper, although the following are needed:
# (Ubuntu alike)
# sudo apt-get install build-essential uuid-dev iasl git gcc-10 nasm python3-distutils

# $1 argument override MYTOOLCHAIN variable, in case you want GCC53 for example

cd "$(dirname $([ -L $0 ] && readlink $0 || echo $0))"
declare -r CLOVERROOT="$PWD"
declare -r SYSNAME="$(uname)"
MYTOOLCHAIN=${1:-GCC53}

# Functions
pathmunge() {
if [[ ! $PATH =~ (^|:)$1(:|$) ]]; then
  if [[ "${2:-}" = "after" ]]; then
    export PATH=$PATH:$1
  else
    export PATH=$1:$PATH
  fi
fi
}

checkXCODE() {
echo "[CHECK XCODE]"
if [[ ! -x /usr/bin/xcodebuild ]]; then
  echo "ERROR: Install Xcode Tools from Apple before using this script."
  exit 1
fi

if [[ ! -d "$(xcode-select --print-path)" ]]; then
  echo "ERROR: Xcode Command Line Tools not selected:"
  echo "       open Xcode.app and go in Preferences->Locations,"
  echo "       and select the Command Line Tools"
  exit 1
fi
}

checkGETTEXT() {
exportPaths
local locations=($(which msgmerge))
if [ "${#locations[@]}" -eq 0 ]; then
  export GETTEXT_PREFIX="${TOOLCHAIN_DIR}"
  "${CLOVERROOT}"/buildgettext.sh
else
  # export gettex prefix to ensure buildpkg.sh will use it
  # without the need to install it again
  export GETTEXT_PREFIX="$(dirname "${locations[0]}")"
fi
}

exportPaths() {
if [[ "$SYSNAME" == Linux ]]; then
  TOOLCHAIN_DIR=${TOOLCHAIN_DIR:-/usr}
elif [[ "$SYSNAME" == Darwin ]]; then
  pathmunge "$(xcode-select --print-path)"/usr/bin
  if [[ -d ~/src/opt/local ]]; then
    TOOLCHAIN_DIR=~/src/opt/local
  else
    TOOLCHAIN_DIR=${TOOLCHAIN_DIR:-"$CLOVERROOT"/toolchain}
  fi
fi

pathmunge "$TOOLCHAIN_DIR"/bin
export TOOLCHAIN_DIR=$TOOLCHAIN_DIR
export DIR_MAIN=${DIR_MAIN:-"$CLOVERROOT"/toolchain}
export DIR_TOOLS=${DIR_TOOLS:-$DIR_MAIN/tools}
export DIR_DOWNLOADS=${DIR_DOWNLOADS:-$DIR_TOOLS/download}
export DIR_LOGS=${DIR_LOGS:-$DIR_TOOLS/logs}
export PREFIX=${TOOLCHAIN_DIR}
}

checkTools() {
# export any env vars before building anything
if [[ "$SYSNAME" == Darwin ]]; then
  checkXCODE
  exportPaths
  local GCC53_BIN="$PREFIX/cross/bin/x86_64-clover-linux-gnu-gcc"
  if [[ $MYTOOLCHAIN == GCC* ]] && [[ ! -x "${GCC53_BIN}" ]]; then
    if [[ $MYTOOLCHAIN == GCC53 ]]; then
      cd "${CLOVERROOT}"
      ./build_gcc10.sh
    else
      MYTOOLCHAIN=XCODE8
    fi
  fi
else
  exportPaths
fi
}

updateClover() {
echo "[UPDATE CLOVER]"
cd "${CLOVERROOT}"
if [[ -d .git ]]; then
  git fetch --all
  git pull origin master
else
  echo "Error: this is not a git repository, can't update!"
fi
}

updateResetClover() {
echo "[UPDATE RESET CLOVER]"
cd "${CLOVERROOT}"
if [[ -d .git ]]; then
  git fetch --all
  git reset --hard origin/master
  git pull origin master
else
  echo "Error: this is not a git repository, can't update!"
fi
}

buildCloverHFSPlus() {
if [[ -f "${CLOVERROOT}"/FileSystems/HFSPlus/X64/HFSPlus.efi ]]; then
  echo "building Clover with HFSPlus"
  buildClover HFSPlus
else
  echo "${CLOVERROOT}/FileSystems/HFSPlus/X64/HFSPlus.efi: no such file!"
  sleep 3
  menu
fi
}

buildClover() {
checkTools

# to force recreation of the Conf folder. You can still use a custom CONF_PATH if you don't want recreation.
rm -rf "$CLOVERROOT"/Conf
mkdir "$CLOVERROOT"/Conf

cd "${CLOVERROOT}"
if [[ -z "$WORKSPACE" ]]; then
  export EDK_TOOLS_PATH="${PWD}"/BaseTools
  set +u
  source ./edksetup.sh BaseTools
  set -u
  cd "$CLOVERROOT"
  WORKSPACE="${PWD}"
fi

echo "[BUILD CLOVER]"
# Run a custom build script if exist (~/src/tools/Scripts/build.sh)
# This allow the user to run ebuild.sh with own parameters
if [[ -x "${DIR_TOOLS}"/Scripts/build.sh ]]; then
  echo "Running custom build script"
  "${DIR_TOOLS}"/Scripts/build.sh "${CLOVERROOT}" $MYTOOLCHAIN
else
  local parameter=${1:-none}
  if [[ "${parameter}" == HFSPlus ]]; then
    ./ebuild.sh -fr -mc --no-usb -D NO_GRUB_DRIVERS_EMBEDDED -D USE_APPLE_HFSPLUS_DRIVER -t $MYTOOLCHAIN
    ./ebuild.sh -fr -D NO_GRUB_DRIVERS_EMBEDDED -D USE_APPLE_HFSPLUS_DRIVER -t $MYTOOLCHAIN
  else
    ./ebuild.sh -fr -mc --no-usb -D NO_GRUB_DRIVERS_EMBEDDED -t $MYTOOLCHAIN
    ./ebuild.sh -fr -D NO_GRUB_DRIVERS_EMBEDDED -t $MYTOOLCHAIN
  fi
fi

# Run a post build script if exist (~/src/tools/Scripts/postbuild.sh)
if [[ -x "${DIR_TOOLS}"/Scripts/postbuild.sh ]]; then
  echo "Running postbuild script"
  "${DIR_TOOLS}"/Scripts/postbuild.sh "${CLOVERROOT}" $MYTOOLCHAIN
fi
}

buildCloverTest() {
checkTools

cd "${CLOVERROOT}"

if [[ -z "$WORKSPACE" ]]; then
  export EDK_TOOLS_PATH="${PWD}"/BaseTools
  set +u
  source ./edksetup.sh BaseTools
  set -u
  cd "$CLOVERROOT"
  WORKSPACE="${PWD}"
fi

echo "[BUILD CLOVER TEST]"
./ebuild.sh -nb -t $MYTOOLCHAIN
}

buildPkg() {
if [[ "$SYSNAME" == Darwin ]]; then
  cd "${CLOVERROOT}"/CloverPackage
  echo "[BUILD PKG]"
  checkXCODE
  checkGETTEXT
  make pkg
else
  echo && echo "can't build pkg on a non Darwin OS!"
fi
}

buildApp() {
local withClover=${1-"none"}
if [[ "$SYSNAME" == Darwin ]]; then
  if [[ -f "${CLOVERROOT}"/CloverPackage/CloverV2/EFI/CLOVER/CLOVERX64.efi ]]; then
    rm -f "${CLOVERROOT}"/CloverPackage/sym/.withV2
    mkdir -p "${CLOVERROOT}"/CloverPackage/sym
    if [[ $withClover == withV2 ]]; then
      touch "${CLOVERROOT}"/CloverPackage/sym/.withV2
    fi
    cd "${CLOVERROOT}"/CloverApp
    echo "[BUILD APP]"
    checkXCODE
    make
  else
    echo && echo "please, build Clover first!"
    sleep 3
  fi
else
  echo && echo "Clover.app can only be built in macOS!"
fi
}

buildIso() {
cd "${CLOVERROOT}"/CloverPackage
echo "[BUILD ISO]"
make iso
}

checkStatus() {
cd "${CLOVERROOT}"
if [[ -d .git ]]; then
  git fetch origin
  git status
else
  echo "Error: this is not a git repository, can't get info!"
fi
}

showdiff() {
cd "${CLOVERROOT}"
if [[ -d .git ]]; then
  git fetch origin
  git diff
else
  echo "Error: this is not a git repository, can't get info!"
fi
}

cleanBaseTools() {
cd "${CLOVERROOT}"/BaseTools
make clean
}

menu() {
echo
echo '------------------------------------------------------------------------'
cd "${CLOVERROOT}"

local lsha1="not a git repo"

if [[ -d .git ]]; then
  lsha1=$(git rev-parse --short HEAD)
fi

echo "buildme, Clover r$(git describe --tags $(git rev-list --tags --max-count=1﻿)) (SHA: $lsha1)"
echo "TOOLCHAIN: $MYTOOLCHAIN (override example: './buildme XCODE8')"
echo
PS3='Please enter your choice: '
options=( 'build Clover'
          'build Clover with HFSPlus'
          'make pkg'
          'make app'
          'make app (with Clover)'
          'make iso'
          'build all'
          'test build (no autogen, no boot files)'
          'status'
          'update Clover'
          'show diff'
          'open CloverV2/EFI/CLOVER directory'
          'update Clover (reset changes)'
          'clean BaseTools'
          'quit')

select opt in "${options[@]}"
do
  case $opt in
    "build Clover")
      buildClover
      break
    ;;
    "build Clover with HFSPlus")
      buildCloverHFSPlus
      break
    ;;
    "make pkg")
      buildPkg
      break
    ;;
    "make app")
      buildApp
      break
    ;;
    "make app (with Clover)")
      buildApp withV2
      break
    ;;
    "make iso")
      buildIso
      break
    ;;
    "build all")
      buildClover
      buildPkg
      buildIso
      buildApp
      break
    ;;
    "test build (no autogen, no boot files)")
      buildCloverTest
      break
    ;;
    "update Clover")
      updateClover
      break
    ;;
    "update Clover (reset changes)")
      read -p "Are you sure? (type y to confirm or any other to negate) " -n 1 -r
      echo
      if [[ $REPLY =~ ^[Yy]$ ]]; then
        updateResetClover
      fi
      break
    ;;
    "status")
      checkStatus
      break
    ;;
    "show diff")
      showdiff
      break
    ;;
    "open CloverV2/EFI/CLOVER directory")
      if [[ -d "${CLOVERROOT}"/CloverPackage/CloverV2/EFI/CLOVER ]]; then
        open "${CLOVERROOT}"/CloverPackage/CloverV2/EFI/CLOVER
      else
        echo && echo "Directory not found. Compile Clover first!!"
        sleep 2
      fi
      break
    ;;
    "clean BaseTools")
      read -p "Are you sure? (type y to confirm or any other to negate) " -n 1 -r
      echo
      if [[ $REPLY =~ ^[Yy]$ ]]; then
        cleanBaseTools
      fi
      break
    ;;
    "quit")
      exit 0
    ;;
    *)
      echo "invalid option $REPLY"
      break
    ;;
  esac
done
menu
}

# Main
set -e
if [[ "$2" == travis ]]; then
  buildClover
  buildPkg
  buildIso
else
  menu
fi
